<?php

namespace fastphp;

use Exception;

class Router
{
    // 路由规则数组
    protected $routes = [];
    // 命名路由映射
    protected $namedRoutes = [];
    // 请求方法
    protected $requestMethod = 'GET';
    // 当前路由组前缀
    protected $groupPrefix = '';
    // 当前路由组中间件
    protected $groupMiddlewares = [];
    // 路由组栈，用于处理嵌套路由组
    protected $groupStack = [];

    /**
     * 添加路由规则
     * 
     * @param string $pattern 路由匹配模式
     * @param string $controller 控制器名称
     * @param string $action 方法名称
     * @param string $name 路由名称（可选）
     * @param string $method HTTP方法（可选，默认GET）
     * @return $this
     */
    public function rule($pattern, $controller, $action, $name = null, $method = 'GET')
    {
        // 应用组前缀
        if (!empty($this->groupPrefix)) {
            $pattern = rtrim($this->groupPrefix, '/') . '/' . ltrim($pattern, '/');
        }

        // 标准化URL路径
        $pattern = $this->normalizePath($pattern);

        $route = new Route($pattern, $controller, $action);
        $route->method = strtoupper($method);

        // 保存路由原始索引，用于后续添加中间件
        $routeIndex = count($this->routes);
        $this->routes[] = $route;

        // 如果提供了路由名称，添加到命名路由映射
        if ($name) {
            $this->namedRoutes[$name] = $route;
        }

        // 应用组中间件
        if (!empty($this->groupMiddlewares)) {
            // 确保路由有名称
            if (empty($route->name)) {
                $route->name = 'route_' . $routeIndex;
            }

            // 获取中间件管理器
            if (isset($GLOBALS['core']) && $GLOBALS['core'] instanceof Core) {
                $middlewareManager = $GLOBALS['core']->get('middleware');
                if ($middlewareManager instanceof MiddlewareManager) {
                    foreach ($this->groupMiddlewares as $middleware) {
                        $middlewareManager->addRoute($route->name, $middleware);
                    }
                }
            }
        }

        return $this;
    }

    /**
     * 添加GET路由
     */
    public function get($pattern, $controller, $action, $name = null)
    {
        return $this->rule($pattern, $controller, $action, $name, 'GET');
    }

    /**
     * 添加POST路由
     */
    public function post($pattern, $controller, $action, $name = null)
    {
        return $this->rule($pattern, $controller, $action, $name, 'POST');
    }

    /**
     * 添加PUT路由
     */
    public function put($pattern, $controller, $action, $name = null)
    {
        return $this->rule($pattern, $controller, $action, $name, 'PUT');
    }

    /**
     * 添加DELETE路由
     */
    public function delete($pattern, $controller, $action, $name = null)
    {
        return $this->rule($pattern, $controller, $action, $name, 'DELETE');
    }

    /**
     * 创建路由组
     * 
     * @param string|array $options 路由组选项，可以是字符串前缀或包含前缀和中间件的数组
     * @param callable $callback 路由组回调函数
     * @return $this
     */
    public function group($options, callable $callback)
    {
        // 保存当前组状态到栈中
        $this->groupStack[] = [
            'prefix' => $this->groupPrefix,
            'middlewares' => $this->groupMiddlewares
        ];

        // 处理路由组选项
        $prefix = '';
        $middlewares = [];

        if (is_string($options)) {
            // 如果是字符串，则作为前缀
            $prefix = $options;
        } elseif (is_array($options)) {
            // 如果是数组，可以包含前缀和中间件
            if (isset($options['prefix'])) {
                $prefix = $options['prefix'];
            }
            if (isset($options['middleware'])) {
                $middlewares = (array) $options['middleware'];
            }
        }

        // 更新当前组状态
        if (!empty($prefix)) {
            $this->groupPrefix = rtrim($this->groupPrefix, '/') . '/' . ltrim($prefix, '/');
        }
        if (!empty($middlewares)) {
            $this->groupMiddlewares = array_merge($this->groupMiddlewares, $middlewares);
        }

        // 执行回调函数，定义组内路由
        call_user_func($callback, $this);

        // 恢复之前的组状态
        $previousGroup = array_pop($this->groupStack);
        if ($previousGroup) {
            $this->groupPrefix = $previousGroup['prefix'];
            $this->groupMiddlewares = $previousGroup['middlewares'];
        } else {
            // 如果栈为空，则重置组状态
            $this->groupPrefix = '';
            $this->groupMiddlewares = [];
        }

        return $this;
    }

    /**
     * 根据路由名称生成URL
     * 
     * @param string $name 路由名称
     * @param array $params 路由参数
     * @return string
     * @throws Exception
     */
    public function url($name, $params = [])
    {
        if (!isset($this->namedRoutes[$name])) {
            throw new Exception("路由名称 '$name' 未定义");
        }

        $route = $this->namedRoutes[$name];
        $url = $route->pattern;

        // 替换路由参数
        foreach ($params as $key => $value) {
            $url = str_replace('{' . $key . '}', $value, $url);
        }

        return $url;
    }

    /**
     * 匹配路由
     * 
     * @param string $requestUri 请求URI
     * @param string $method HTTP方法
     * @return Route|null 匹配的路由对象，如果没有匹配则返回null
     */
    public function match($requestUri, $method = null)
    {
        // 标准化请求URI
        $requestUri = $this->normalizePath($requestUri);

        // 使用当前请求方法或传入的方法
        $method = $method ?: $this->getRequestMethod();

        // 调试信息
        if (defined('APP_DEBUG') && APP_DEBUG) {
            // echo "尝试匹配路由: URI='{$requestUri}', 方法='{$method}'<br>";
        }

        foreach ($this->routes as $route) {
            // 调试信息
            // if (defined('APP_DEBUG') && APP_DEBUG) {
            //     echo "检查路由: 模式='{$route->pattern}', 方法='{$route->method}', 控制器='{$route->controller}', 动作='{$route->action}'<br>";
            // }

            // 检查HTTP方法是否匹配
            if ($route->method && $route->method !== $method) {
                continue;
            }

            // 转换路由模式为正则表达式
            $regexPattern = $this->convertPatternToRegex($route->pattern);

            if (preg_match($regexPattern, $requestUri, $matches)) {
                // 处理捕获的参数
                array_shift($matches); // 移除完整匹配

                // 提取命名参数
                $this->extractParameters($route, $matches);

                return $route;
            }
        }

        return null;
    }

    /**
     * 分发请求到相应的控制器和动作
     * 
     * @param string $requestUri 请求URI
     * @return mixed 控制器动作的返回值
     * @throws Exception
     */
    public function dispatch($requestUri)
    {
        if (empty($requestUri)) {
            $requestUri = '/';
        }

        try {
            $route = $this->match($requestUri);

            if (!$route) {
                throw new Exception("未找到匹配的路由: $requestUri");
            }

            $controllerName = $route->controller;
            $actionName = $route->action;

            // 构造完整的控制器类名
            $controllerClassName = 'application\\controller\\' . ucfirst($controllerName);

            // 检查控制器文件是否存在 - 确保路径正确
            $controllerFile = APP_PATH . DIRECTORY_SEPARATOR . 'application' . DIRECTORY_SEPARATOR . 'controller' . DIRECTORY_SEPARATOR . ucfirst($controllerName) . '.php';

            if (!file_exists($controllerFile)) {
                throw new Exception("控制器文件不存在: $controllerFile");
            }

            // 包含控制器文件
            require_once $controllerFile;

            // 检查控制器类是否存在
            if (!class_exists($controllerClassName)) {
                throw new Exception("控制器类不存在: $controllerClassName");
            }

            // 实例化控制器
            $controller = new $controllerClassName($controllerName, $actionName);

            // 检查动作方法是否存在
            if (!method_exists($controller, $actionName)) {
                throw new Exception("动作方法不存在: $actionName");
            }

            // 创建控制器动作闭包
            $action = function ($request, $response) use ($controller, $actionName, $route) {
                // 调用动作方法并获取响应
                $result = call_user_func_array([$controller, $actionName], $route->parameters);

                // 如果控制器返回了响应，则使用它
                if ($result instanceof Response) {
                    return $result;
                }

                // 否则返回默认响应
                return $response;
            };

            // 获取Core实例（通过容器或者全局实例）
            if (isset($GLOBALS['core']) && $GLOBALS['core'] instanceof Core) {
                $core = $GLOBALS['core'];

                // 通过中间件管理器执行动作
                $response = $core->get('middleware')->execute(
                    $core->get('request'),
                    $core->get('response'),
                    $action,
                    $route->name
                );

                // 将中间件执行结果赋值给$result变量，确保函数返回时变量已定义
                $result = $response;
            } else {
                // 如果没有中间件系统，直接执行动作
                $result = $action(null, null);
            }

            return $result;
        } catch (Exception $e) {
            // 处理异常
            $this->handleException($e);
            return null;
        }
    }

    /**
     * 处理异常
     * 
     * @param Exception $e
     */
    protected function handleException(Exception $e)
    {
        if (defined('APP_DEBUG') && APP_DEBUG) {
            // 调试模式下显示详细错误信息
            echo '<div style="background: #ffeeee; border: 1px solid #ff0000; padding: 10px; margin: 10px;">';
            echo '<h2>路由错误</h2>';
            echo '<p>' . $e->getMessage() . '</p>';
            echo '<pre>' . $e->getTraceAsString() . '</pre>';
            echo '</div>';
        } else {
            // 非调试模式下显示默认错误页面
            if (!APP_DEBUG) {
                // require_once DefErrorPage;
            } else {
                echo '请求的页面不存在或发生错误';
            }
        }
    }

    /**
     * 获取当前请求方法
     * 
     * @return string
     */
    protected function getRequestMethod()
    {
        if (isset($_SERVER['REQUEST_METHOD'])) {
            return strtoupper($_SERVER['REQUEST_METHOD']);
        }
        return 'GET';
    }

    /**
     * 标准化路径
     * 
     * @param string $path
     * @return string
     */
    protected function normalizePath($path)
    {
        // 确保路径以/开头
        if ($path === '' || $path[0] !== '/') {
            $path = '/' . $path;
        }

        // 移除末尾的斜杠（除了根路径）
        if ($path !== '/' && substr($path, -1) === '/') {
            $path = substr($path, 0, -1);
        }

        return $path;
    }

    /**
     * 将路由模式转换为正则表达式
     * 
     * @param string $pattern
     * @return string
     */
    protected function convertPatternToRegex($pattern)
    {
        // 处理命名参数 {param} 或 {param:pattern}
        // 先保存需要保留的参数模式
        $params = [];
        $pattern = preg_replace_callback('/\{([a-zA-Z0-9_]+)(?::([^}]+))?\}/', function ($matches) use (&$params) {
            $paramName = $matches[1];
            $paramPattern = isset($matches[2]) ? $matches[2] : '[^/]+';
            $placeholder = '___PARAM_' . $paramName . '___';
            $params[$placeholder] = '(?<' . $paramName . '>' . $paramPattern . ')';
            return $placeholder;
        }, $pattern);

        // 转义其他特殊字符
        $pattern = preg_quote($pattern, '/');

        // 恢复参数模式
        foreach ($params as $placeholder => $paramRegex) {
            $pattern = str_replace($placeholder, $paramRegex, $pattern);
        }

        // 添加开始和结束标记
        return '/^' . $pattern . '$/';
    }

    /**
     * 提取路由参数
     * 
     * @param Route $route
     * @param array $matches
     */
    protected function extractParameters(Route $route, array $matches)
    {
        // 检查是否有命名参数
        foreach ($matches as $key => $value) {
            if (is_string($key)) {
                // 命名参数
                $route->parameters[$key] = $value;
            }
        }

        // 如果没有命名参数，使用数字索引（保持向后兼容）
        if (empty($route->parameters) && !empty($matches)) {
            $route->parameters = array_values($matches);
        }
    }

    /**
     * 为当前路由添加中间件
     * 
     * @param string|array $middleware 中间件类名或别名
     * @return $this
     */
    public function middleware($middleware)
    {
        // 获取最后添加的路由
        $lastRouteIndex = count($this->routes) - 1;
        if ($lastRouteIndex >= 0) {
            $lastRoute = $this->routes[$lastRouteIndex];
            // 确保路由有名称
            if (empty($lastRoute->name)) {
                // 为匿名路由生成一个唯一名称
                $lastRoute->name = 'route_' . $lastRouteIndex;
            }

            // 获取中间件管理器
            if (isset($GLOBALS['core']) && $GLOBALS['core'] instanceof Core) {
                $middlewareManager = $GLOBALS['core']->get('middleware');
                if ($middlewareManager instanceof MiddlewareManager) {
                    // 为路由添加中间件
                    $middlewareManager->addRoute($lastRoute->name, $middleware);
                }
            }
        }
        return $this;
    }
}
